package admin

import (
	"context"
	"micro-oauth/datamodels/autherror"
	model "micro-oauth/datamodels"
	"micro-oauth/datamodels/params"
	"micro-oauth/utils"
)

func (s *AdminServiceImpl) AddScope(ctx context.Context, req *params.ScopeCreateRequest) (*model.Scope, autherror.HexError) {
	pId := ctx.Value("partner_id").(uint64)
	if s.isHexPartner(pId) {
		return nil, autherror.PermissionDenied("not hex user can operate")
	}
	req.PartnerId = pId
	uId := ctx.Value("user_id").(uint64)
	err := req.Validate()
	if err != nil {
		return nil, autherror.InvalidData(err.Error())
	}

	listReq := &params.ScopeListRequest{
		ListRequest: params.ListRequest{
			PartnerId: req.PartnerId,
		},
		Name: req.Name,
	}
	_, nameCount, err1 := s.repoService.ListScope(listReq)
	listReq.Name = ""
	listReq.Code = req.Code
	_, codeCount, err2 := s.repoService.ListScope(listReq)
	if err1 != nil || err2 != nil {
		var err error
		if err1 != nil {
			err = err1
		} else {
			err = err2
		}
		return nil, autherror.DBError(err.Error())
	}
	if nameCount != 0 {
		return nil, autherror.InvalidData("name duplicate")
	}
	if codeCount != 0 {
		return nil, autherror.InvalidData("code duplicate")
	}
	scopeId,_ := utils.GetId()
	scope := &model.Scope{
		PartnerId:   req.PartnerId,
		Name:        req.Name,
		Code:        req.Code,
		Description: req.Description,
		MyGormModel: model.MyGormModel{
			Id: scopeId,
			CreatedBy: uId,
			UpdatedBy: uId,
		},
	}
	err = s.repoService.AddScope(scope)
	if err != nil {
		return nil, autherror.DBError(err.Error())
	}
	return scope, nil
}

func (s *AdminServiceImpl) UpdateScope(ctx context.Context, req *params.ScopeUpdateRequest) (*model.Scope, autherror.HexError) {
	pId := ctx.Value("partner_id").(uint64)
	if s.isHexPartner(pId) {
		return nil, autherror.PermissionDenied("not hex user can operate")
	}
	req.PartnerId = pId
	if err := req.Validate(); err != nil {
		return nil, autherror.InvalidData(err.Error())
	}

	scope := s.repoService.GetScopeById(req.Id)
	if scope == nil {
		return nil, autherror.NotFound("can't find scope")
	}

	listReq := &params.ScopeListRequest{
		ListRequest: params.ListRequest{
			Exclude: params.Exclude{
				Id: req.Id,
			},
		},
		Name: req.Name,
	}
	_, nameCount, err1 := s.repoService.ListScope(listReq)
	listReq.Name = ""
	listReq.Code = req.Code
	_, codeCount, err2 := s.repoService.ListScope(listReq)

	if err1 != nil {
		return nil, autherror.DBError(err1.Error())
	}
	if err2 != nil {
		return nil, autherror.DBError(err2.Error())
	}
	if codeCount != 0 {
		return nil, autherror.InvalidData("code duplicate")
	}
	if nameCount != 0 {
		return nil, autherror.InvalidData("name duplicate")
	}

	scope.Name = req.Name
	scope.Code = req.Code
	scope.Description = req.Description
	err := s.repoService.UpdateScope(scope)
	if err != nil {
		return nil, autherror.DBError(err.Error())
	}
	return scope, nil
}

func (s *AdminServiceImpl) ListScope(ctx context.Context, req *params.ScopeListRequest) (scopes []*model.Scope, total uint64, hexerr autherror.HexError) {
	pId := ctx.Value("partner_id").(uint64)
	if s.isHexPartner(pId) {
		return nil, 0, autherror.PermissionDenied("not hex user can operate")
	}
	req.ListRequest.PartnerId = req.PartnerId
	scopes, total, err := s.repoService.ListScope(req)
	if err != nil {
		return nil, 0, autherror.DBError(err.Error())
	}
	return scopes, total, nil
}

func (s *AdminServiceImpl) GetScope(ctx context.Context, scopeId uint64) (*model.Scope, autherror.HexError) {
	pId := ctx.Value("partner_id").(uint64)
	if s.isHexPartner(pId) {
		return nil, autherror.PermissionDenied("not hex user can operate")
	}

	scope := s.repoService.GetScopeById(scopeId)
	if scope == nil {
		return nil, autherror.NotFound("can't find scope")
	}
	return scope, nil
}

func (s *AdminServiceImpl) DeleteScope(ctx context.Context, scopeId uint64) autherror.HexError {
	pId := ctx.Value("partner_id").(uint64)
	if s.isHexPartner(pId) {
		return autherror.PermissionDenied("not hex user can operate")
	}
	err := s.repoService.DeleteScope(scopeId)
	if err != nil {
		return autherror.DBError(err.Error())
	}
	return nil
}
